INT p_bsrch(INT nrec, INT (*compf)(), INT *pmid, UBYTE *pmatch); Use a binary search algorithm to find the record, in an array of nrec records, that is adjacent to, if not identical with, the record pointed to by pmatch. Writes the record number of the found record to *pmid and returns: 0 <0 >0 the found record is equal to *pmatch *pmatch belongs before record number *pmid *pmatch belongs after record number *pmid If two or more array elements exactly match the record at pmatch, the return value will be zero and *pmid will contain the index of any one of the matching elements. Each time p_bsrch needs to compare a record with the record at pmatch it calls: compf(n,pmatch); where n is the index of the record to be compared. This user-supplied comparison routine should return: 0 <0 >0 *pmatch is equal to record number n *pmatch is before record number n *pmatch is after record number n As with any binary search, the array must be ordered. For p_bsrch, it should be ordered with respect to compf, the user-supplied comparison routine. In most cases the set of records will be a fixed array, but any arrangement which allows the routine to identify a record by index (e.g. hashing) will be suitable. Likewise, pmatch may be any address suitable for interpretation by compf, since pmatch is not used inside p_bsrch, other than being passed to compf. This allows code using p_bsrch to be re-entrant. If the whole table is created before being searched it is, in general, quicker to build the table unordered and then sort it (see p_qsort) than to build the table in sequence by insertion. Example LOCAL_D INT array[]={5,8,13,19,25,30,41,48,51,62,70,76,80,90,98}; LOCAL_C intcompare(INT n,INT *pmatch) { INT f,m; f=array[n]; m=*pmatch; if (f==m) return(0); return(m>f?1:-1); } VOID find(INT match) { INT nrec; /* number of INTs in the array */ INT result; INT mid; TEXT *pstr; nrec=sizeof(array)/sizeof(INT); result=p_bsrch(nrec,(INT (*)())intcompare,&mid,&match); if (!result) p_printf("%d matches record number %d",match,mid); else { pstr=result<0?"before":"after"; p_printf("%d belongs %s %d",match,pstr,array[mid]); } } p_qsort Sort an array of records (p_qsort) tc INT p_qsort(INT nrec, INT (*ordf)(), VOID (*excf)(), UBYTE *base) Sort a set of records into ascending order, using the quicksort xe "quicksort" algorithm. There are nrec records to sort. Each time the routine needs to compare two of these records it calls: (*ordf)(n,m,base); where n and m are the indexes of the two records to compare (starting at zero), and base is a parameter that may be used or ignored by the ordering function. The ordering function, ordf, should return: 0 <0 >0 record number n is equal to record number m record number n is less than record number m record number n is greater than record number m Each time the routine needs to exchange two records it calls: (*excf)(n,m,base); where n and m are the indexes (starting at zero) of the two records to exchange. The user-supplied exchange routine should exchange the records indexed by n and m. Again, the user-supplied exchange function is free to use or ignore base, but its use should be consistent between the ordering and exchange functions. Normally, base will represent the address of a fixed length array, but any method of storing records may be used, as long as the records can be accessed using the indices. The value of base is not used inside p_qsort, but is passed down to both the ordering and exchange functions to enable the writing of re-entrant code that uses p_qsort. The routine uses its own stack, declared locally, to avoid the need to be called recursively. This stack is 150*sizeof(INT) in length and, as such, could cause the main stack to overflow if the routine is called from too deep inside a program. The function p_qsort returns zero if successful, else a negative error. An error return value of E_GEN_FAIL is returned if the internal stack overflows. This is, however, unlikely as an experiment to sort 50000 elements used only 80 stack elements. If this error is returned, the routine can be called again, as it is likely that the array has been rearranged enough to permit the successful completion of a second attempt. Example LOCAL_D INT array[]={98,90,80,76,70,62,51,48,41,30,25,19,13,8,5}; LOCAL_C intcompare(INT first,INT second,INT *array) { INT f,s; f=*(array+first); s=*(array+second); if (s==f) return(0); return(f>s?1:-1); } LOCAL_C VOID intexchange(INT first,INT second,INT *array) { INT r; r=*(array+first); *(array+first)=*(array+second); *(array+second)=r; } LOCAL_C VOID sort(VOID) { INT n; /* number of INTs in the array */ n=sizeof(array)/sizeof(INT); if (p_qsort(n,intcompare,intexchange,&array[0])) p_panic("Too many partitions"); }